
/***************************************************************************
 *   Copyright (C) 1997 to 2004 by Jonathan Duddington                     *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write see:                           *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "wimp.h"
#include "dbox.h"

#include "narc.h"
#include "hdrs.h"


/********************************************************************************/
/*   Routines specific to the structure of the data                             */
/********************************************************************************/





static int fold_next_count[N_FOLD_LEVELS];



int fold_vector_to_ref(FOLDREC *fr, int *vector, int n_levels)
/************************************************************/
/* Returns an index into the index list */
{
	int  level;
	int  i;
	int  ix;
	int  n;
	int  lev;


	for(i=0; i<=n_levels; i++)
		fold_next_count[i] = vector[i];

	if(fr->type >= 1)
	{
		return(fold2_vector_to_ref(fr,vector,n_levels));
	}

	ix = 0;
	for(level=0; level<=n_levels; level++)
	{
		n = vector[level];

		i = 0;
		while((i <= n)  && (ix < fr->n_entries))
		{
			lev = fr->ixlist[ix++] >> IXLEV;
			if(lev > fr->display_levels)
				lev = fr->display_levels;

			if(lev <= level)
			{
				i++;
			}
		}

		if(i <= n)
			return(-1);   /* run off end of list */

		ix--;
	}
	return(ix);
}   /* end of fold_vector_to_ref */




void fold_ref_to_vector(FOLDREC *fr, int ref, int level, int *vector)
/*******************************************************************/
{
	int  i;
	int  ix;
	int  count;
	int  start=0;
	int  lev;


	/* only implemented for list type, not tree type */

	for(lev=0; lev<=level; lev++)
	{
		count=0;
		for(ix=start; ix<=ref; ix++)
		{
			i = fr->ixlist[ix] >> IXLEV;
			if(i > fr->display_levels)
				i = fr->display_levels;
			if(i <= lev)
			{
				start = ix;
				count++;
			}
			vector[lev] = count-1;
		}
	}
}   /* end of fold_ref_to_vector */




int fold_count_level(FOLDREC *fr, int ix, int level)
/**************************************************/
/* How many dependents of this level of the vector,
   from position ix in the index list  */
{
	int  i;
	int  lev;

	if(fr->type >= 1)
	{
		return(fold2_count_level(fr,ix,level));
	}

	i = 1;
	ix++;
	while(ix < fr->n_entries)
	{
		lev = fr->ixlist[ix++] >> IXLEV;
		if(lev > fr->display_levels)
			lev = fr->display_levels;

		if(lev <= level)
			break;

		if(lev == (level+1))
			i++;
	}
	return(i);
}   /* end of fold_count_level */



int fold_count_at_level(FOLDREC *fr, int ix, int level, int *end_ix)
/******************************************************************/
/* Find the start and end of a level */
{
	int  end;

	if(level <= 0)
	{
		*end_ix = fr->n_entries-1;  /* the whole list */
		return(0);
	}

	end = ix + 1;
	while((ix > 0) && ((fr->ixlist[ix] >> IXLEV) >= level))
	{
		ix--;
	}

	while((end < fr->n_entries) && ((fr->ixlist[end] >> IXLEV) >= level))
	{
		end++;
	}

	*end_ix = end;
	return(ix);
}  /* end of fold_count_at_level */




int fold_next_right(FOLDREC *fr, int ix, int level)
/*************************************************/
/* Find next item at the same level */
{
	int  lev;

	if(fr->type >= 1)
	{
		return(fold2_next_right(fr,ix,level));
	}

	ix++;
	while(ix < fr->n_entries)
	{
		if((lev = fr->ixlist[ix] >> IXLEV) > fr->display_levels)
			lev = fr->display_levels;

		if(lev == level)
			break;

		ix++;
	}

	if(ix >= fr->n_entries)
		return(-1);
	else
		return(ix);
}   /* end of fold_next_right */




int fold_next_down(FOLDREC *fr, int ix, int level)
/************************************************/
/* Find next item at lower level */
{
	if(fr->type >= 1)
	{
		return(fold2_next_down(fr,ix,level));
	}
	return(ix);
}   /* end of fold_next_down */





/********************************************************************************/
/*   General Fold Routines                                                      */
/********************************************************************************/



int fold_next(FOLDREC *fr, int ix, int *level)
/****************************************/
/* Get the next ix and level to be displayed, after the specified ix and level */
{
	int  lev;

	if((fr->type >= 1) && (ix == 0))
		return(0);    /* root */


	lev = *level;

	if((lev < fr->open_levels) && (ix == fr->open_ref[lev]) && (fr->n_open[lev+1] > 0))
	{
		ix = fold_next_down(fr,ix,lev);
		lev++;
		fold_next_count[lev] = 0;
	}
	else
	{
		fold_next_count[lev]++;
		if(fold_next_count[lev] >= fr->n_open[lev])
		{
			while(--lev >= 0)
			{
				if(++fold_next_count[lev] < fr->n_open[lev])
				{
					break;
				}
			}
			ix = fold_next_right(fr,fr->open_ref[lev],lev);
		}
		else
		{
			ix = fold_next_right(fr,ix,lev);
		}
	}

	*level = lev;    /* level of -1 indicates end of list */
	return(ix);
}   /* end of fold_next */




int fold_vector_to_line(FOLDREC *fr, int *vector, int level)
/**********************************************************/
/* item at vector must be open */
{
	int  linenum=0;
	int  lev;
	int  open_line=0;

	/*   for(lev=0; lev < fr->open_levels; lev++) */
	for(lev=0; lev<=level; lev++)
	{
		open_line += fr->open_vect[lev];
	}

	for(lev=0; lev<=level; lev++)
	{
		linenum += vector[lev];
	}

	if(linenum > open_line)
	{
		for( ; lev <= fr->open_levels; lev++)
		{
			linenum += fr->n_open[lev];
		}
	}

	return(linenum + level);
}   /* end of fold_vector_to_line */




int fold_ref_to_line(FOLDREC *fr, int ref, int level)
/***************************************************/
/* Gives line number for the item, or -1 if not open */
{
	int start_ix;
	int end_ix;
	int vector[N_FOLD_LEVELS];

	start_ix = fr->open_ref[level-1];
	end_ix = start_ix + fr->n_open[level];

	if((ref < start_ix) || (ref >= end_ix))
		return(-1);

	memcpy(vector,fr->open_vect,sizeof(vector));

	vector[level] = ref-start_ix;

	return(fold_vector_to_line(fr,vector,level));
}   /* end of fold_ref_to_line */




void fold_remove_ref(FOLDREC *fr, int ref)
/****************************************/
/* If the item is open, decrement the n_open count */
{
	int  start_ix;
	int  level;
	int  ix;

	level = fr->open_levels;
	if(level < 0)
		return;

	if(level <= 0)
		start_ix = 0;
	else
		start_ix = fr->open_ref[level-1];

	ix = ref - start_ix;

	if((ix >= 0) && (ix < fr->n_open[level]))
		fr->n_open[level]--;
}   /* end of fold_remove_ref */





void fold_line_to_vector(FOLDREC *fr, int line, int *vector, int *v_level)
/************************************************************************/
{
	int  count;
	int  level;
	int  below;
	int  last_level=0;

	count = 0;
	for(level=0; level<fr->open_levels; level++)
	{
		if(line <= (fr->open_vect[level] + count))
		{
			vector[level] = line - count;
			*v_level = level;
			return;
		}

		vector[level] = fr->open_vect[level];
		count += fr->open_vect[level] + 1;
	}

	if(line < (fr->n_open[level] + count))
	{
		vector[level] = line - count;
		*v_level = level;
		return;
	}
	vector[level] = fr->n_open[level] - 1;
	count += fr->n_open[level];
	last_level = level;


	for(level=fr->open_levels-1; level>=0; level--)
	{
		below = fr->n_open[level] - fr->open_vect[level] - 1;
		if(below > 0)
			last_level = level;

		if((line - count) < below)
		{
			vector[level] += (line - count + 1);
			*v_level = level;
			return;
		}
		else
		{
			vector[level] = fr->n_open[level] - 1;
			count += below;
		}
	}

	/* line is below all items, select the last */
	*v_level = last_level;
}   /* end of fold_line_to_vector */




int fold_line_to_ref(FOLDREC *fr, int line, int *level, int *vector_out)
/***************************************************************/
{
	int  i;
	int  lev;
	int  ref;
	int  vector[N_FOLD_LEVELS];

	fold_line_to_vector(fr,line,vector,&lev);

	if(vector_out != NULL)
	{
		for(i=0; i<=lev; i++)
			vector_out[i] = vector[i];
	}
	ref = fold_vector_to_ref(fr,vector,lev);
	*level = lev;
	return(ref);
}   /* end of fold_line_to_ref */




void fold_open_at_vector(FOLDREC *fr, int *vector, int level)
/***********************************************************/
{
	int  lev;
	int  ix;

	if(level >= (N_FOLD_LEVELS - 1))
		return;

	if(vector[0] < 0)
	{
		fr->open_levels = 0;
		return;
	}

	for(lev=0; lev<=level; lev++)
	{
		fr->open_vect[lev] = vector[lev];
	}
	fr->open_levels = level+1;

	/* find the data index for each level at the open point */
	for(lev=0; lev<=level; lev++)
	{
		fr->open_ref[lev] = ix = fold_vector_to_ref(fr,fr->open_vect,lev);
		fr->n_open[lev+1] = fold_count_level(fr,ix,lev);
	}

}   /* end of fold_open_at_vector */




void fold_open_at_line(FOLDREC *fr, int line)
/*******************************************/
{
	int level;
	int vector[N_FOLD_LEVELS];

	fold_line_to_vector(fr,line,vector,&level);

	fold_open_at_vector(fr,vector,level);
}   /* end of fold_open_at_line */




void fold_close_level(FOLDREC *fr, int level)
/*******************************************/
/* Close from this level downwards */
{
	int  lev;

	for(lev=level; lev<=fr->open_levels; lev++)
	{
		fr->open_ref[lev] = 0;
		fr->open_vect[lev] = 0;
	}
	fr->open_levels = level;
}   /* end of fold_close_level */




int fold_n_lines(FOLDREC *fr, int level)
/**************************************/
/* Find number of visible lines at specified level */
{
	int  lev;
	int  count =0;

	for(lev=level; lev <= fr->open_levels; lev++)
	{
		count += fr->n_open[lev];
	}
	fr->n_lines = count;
	return(count);
}   /* end of fold_n_lines */




int fold_linenum_open(FOLDREC *fr, int level)
/*******************************************/
/* Find the line number where the list is open at the specified level */
{
	int linenum=0;
	int lev;

	if(level >= fr->open_levels)
		level = fr->open_levels;

	for(lev=0; lev<=level; lev++)
	{
		linenum += fr->open_vect[lev];
	}
	return(linenum + level);
}   /* end of fold_linenum_open */




int fold_is_line_open(FOLDREC *fr, int line)
/******************************************/
/* Check whether line is opened.
   If so, return level, if not return -1 */
{
	int  lev;
	int line_level;
	int vector[N_FOLD_LEVELS];

	fold_line_to_vector(fr,line,vector,&line_level);


	for(lev=0; lev<=line_level; lev++)
	{
		if((lev >= fr->open_levels) || (vector[lev] != fr->open_vect[lev]))
			return(-1);
	}
	return(line_level);
}   /* end of fold_is_line_open */




